/**************************************************************************************************
* Title: SmurfsPhysicsManager.h
* Authors: Gael Huber, Erin Mooney
* Description: Manages updating of physics
**************************************************************************************************/
#ifndef __PHYSICSMANAGER_H__
#define __PHYSICSMANAGER_H__

#include <vector>
#include "SmurfsRigidBody.h"
#include "SmurfsSingleton.h"
#include "SmurfsQuaternion.h"
#include "SmurfsSphere.h"
#include "SmurfsPolygon.h"
#include "SmurfsVector2.h"
#include "SmurfsPlane.h"
#include "SmurfsCollisionStructures.h"
#include "SmurfsTimer.h"
#include "SmurfsMatrix.h"
#include "Octree.h"

// Gravity constant
#define GRAVITY -4.9f

class PhysicsManager : public Singleton<PhysicsManager> {
public:
	PhysicsManager(void);	// Constructor
	virtual ~PhysicsManager(void);	// Destructor

	void startUp(void);		// Initialize OpenGL
	void shutDown(void);	// Shutdown

	static PhysicsManager& getSingleton(void);	// Get the singleton instance
	static PhysicsManager* getSingletonPtr(void);	// Get the singleton pointer

	void update(void);	// Render the scene
	void addToWorld(RigidBody* obj);	// Add an object to the scene
	void removeFromWorld(RigidBody* obj);	// Remove an object from the scene
	void initializeTimer(void);	// Must be done separately from rest of world as the timer run internal to physics must have a very short interval

	void buildTerrainTree(SmurfsPolygon*** polygons, int width, int height, Vector3 treeCenter, Vector3 treeSize);	// builds the tree
	void destroyTerrainTree(void);

	bool grounded;	// Is the player grounded?

private:
	bool triangleSphereCollision(Sphere* s, SmurfsPolygon* t);	// Check for a collision between a sphere and a triangle
	bool checkPointInTriangle(Vector3 point, Vector3 pa, Vector3 pb, Vector3 pc);	// Check whether a 
		// point lies inside the given triangle
	bool getLowestRoot(float a, float b, float c, float maxR, float* root);	// Solve a quadratic 
		// equation and return the lowest root below a certain threshhold (maxR)

	void collideAndSlide(Sphere* body);	// Respond to collision
	Vector3 collideWithWorld(Sphere* body, Vector3 position, Vector3 velocity);	// Collide with the world!
	void testCollisions(Sphere* body);	// Check a single object for collisions against the world
	void testCollisionsTerrain(Sphere* body, OctreeNode* tree);		// Test for 
		// collisions against the terrain
	bool testSphereOBB(Sphere* s, RigidBody* b, Vector3 &p);	// Returns true if sphere s intersects OBB b, 
		// false otherwise. The point p on the OBB closest to the sphere center is also returned.
	bool testObbObb(RigidBody &a, RigidBody &b);	// Test for collision between two OBBs
	void applyFriction(Sphere* body);	// Apply friction to a sphere


	std::vector<RigidBody*> bodyList;	// List of objects to update
	Octree* tree;		// the terrain tree

	// Collision variables
	bool foundCollision;
	float nearestDistance;
	Vector3 intersectionPoint;
	int collisionRecursionDepth;
	Vector3 eVelocity;
	Vector3 eNormalizedVelocity;
	OctreeNode** ancestorStack;
	TERRAIN_TYPE terrainType;	// The type of terrain currently being collided against

	// Time keeping
	Timer* timer;
	float dt;
};

#endif